<?php
/**
 * Actions modify the AMF message PER BODY
 * This allows batching of calls
 * 
 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
 * @copyright (c) 2003 amfphp.org
 * @package flashservices
 * @subpackage filters
 * @version $Id: Filters.php,v 1.6 2005/04/02   18:37:51 pmineault Exp $
 */

/**
 * Catches any special request types and classifies as required
 */
function adapterAction (&$amfbody) {
	$baseClassPath = $GLOBALS['amfphp']['classPath'];

	$uriclasspath = "";
	$classname = "";
	$classpath = "";
	$methodname = "";
	$isWebServiceURI = false;

	$target = $amfbody->targetURI;
	
	if (strpos($target, "http://") === false && strpos($target, "https://") === false) { // check for a http link which means web service
		$lpos = strrpos($target, ".");
		if ($lpos === false) {
			//Check to see if this is in fact a RemotingMessage
			$body = $amfbody->getValue();
			$handled = false;
			if(isset($body[0]['_explicitType']))
			{
				
				$messageType = $body[0]['_explicitType'];
				if($messageType == 'flex.messaging.messages.RemotingMessage')
				{
					$handled = true;
					$amfbody->setValue($body[0]['body']);
					$amfbody->setSpecialHandling("RemotingMessage");
					$amfbody->setMetadata("clientId", $body[0]['clientId']);
					$amfbody->setMetadata("messageId", $body[0]['messageId']);
					
					$methodname = $body[0]['operation'];
					$classAndPackage = $body[0]['source'];
					$lpos = strrpos($classAndPackage, ".");
					if($lpos !== FALSE)
					{
						$classname = substr($classAndPackage, $lpos + 1);
					}
					else
					{
						$classname = $classAndPackage;
					}
					$uriclasspath = str_replace('.','/',$classAndPackage) . '.php';
					$classpath = $baseClassPath . $uriclasspath;
				}
				elseif($messageType == "flex.messaging.messages.CommandMessage")
				{
					if($body[0]['operation'] == 5)
					{
						$handled = true;
						$amfbody->setSpecialHandling("Ping");
						$amfbody->setMetadata("clientId", $body[0]['clientId']);
						$amfbody->setMetadata("messageId", $body[0]['messageId']);
						$amfbody->noExec = true;
					}
				}
				
				if(!$handled)
				{
					$uriclasspath = "amfphp/Amf3Broker.php";
					$classpath = $baseClassPath . "amfphp/Amf3Broker.php";
					$classname = "Amf3Broker";
					$methodname = "handleMessage";
				}
			}
		} else {
			$methodname = substr($target, $lpos + 1);
			$trunced = substr($target, 0, $lpos);
			$lpos = strrpos($trunced, ".");
			if ($lpos === false) {
				$classname = $trunced;
				if ($classname == "PageAbleResult" && $methodname == 'getRecords') {
					$val = $amfbody->getValue();
					$id = $val[0];
					$keys = explode("=", $id);
					$currset = intval($keys[1]);
					
					$set = $_SESSION['amfphp_recordsets'][$currset];
					
					$uriclasspath = $set['class'];
					$classpath = $baseClassPath . $set['class'];
					$methodname = $set['method'];
					
					$classname = substr(strrchr('/' . $set['class'], '/'), 1, -4);
					
					//Now set args for body
					$amfbody->setValue(array_merge($set['args'], array($val[1], $val[2])));
					
					//Tell amfbody that this is a dynamic paged resultset
					$amfbody->setSpecialHandling('pageFetch');
				} 
				else if($classname == "PageAbleResult" && $methodname == 'release')
				{
					$amfbody->setSpecialHandling('pageRelease');
					$amfbody->noExec = true;
				}
				else {
					$uriclasspath = $trunced . ".php";
					$classpath = $baseClassPath . $trunced . ".php";
				} 
			} else {
				$classname = substr($trunced, $lpos + 1);
				$classpath = $baseClassPath . str_replace(".", "/", $trunced) . ".php"; // removed to strip the basecp out of the equation here
				$uriclasspath = str_replace(".", "/", $trunced) . ".php"; // removed to strip the basecp out of the equation here
			} 
		}
	} else { // launch a web service and not a php service
		$amfbody->setSpecialHandling('ws');
		$amfbody->noExec = true;
		$rdot = strrpos($target, ".");
		$classpath = substr($target, 0, $rdot);
		$methodname = substr($target, $rdot + 1);
	} 

	$amfbody->classPath = $classpath;
	$amfbody->uriClassPath = $uriclasspath;
	$amfbody->className = $classname;
	$amfbody->methodName = $methodname;

	return true;
} 

/**
 * ExecutionAction executes the required methods
 */
function executionAction (&$amfbody) 
{
	$specialHandling = $amfbody->getSpecialHandling();

	if (!$amfbody->isSpecialHandling() || $amfbody->isSpecialHandling(array('describeService', 'pageFetch', 'RemotingMessage')))
	{
		$construct = &$amfbody->getClassConstruct();
		$method = $amfbody->methodName;
		$args = $amfbody->getValue();
		
		if($specialHandling == 'describeService')
		{               
			include_once(AMFPHP_BASE . "util/DescribeService.php");
			$ds = new DescribeService();
			$results = $ds->describe($construct, $amfbody->className);
		}
		else if($specialHandling == 'pageFetch')
		{
			$args[count($args) - 2] = $args[count($args) - 2] - 1;
			
			$dataset = Executive::doMethodCall($amfbody, $construct, $method, $args);
			$results = array("cursor" => $args[count($args) - 2] + 1,
							 "data" => $dataset);
			$amfbody->setMetadata('type', '__DYNAMIC_PAGE__');
		}
		else
		{
			/*
			if(isset($construct->methodTable[$method]['pagesize']))
			{
				//Check if counting method was overriden
				if(isset($construct->methodTable[$method]['countMethod']))
				{
					$counter = $construct->methodTable[$method]['countMethod'];
				}
				else
				{
					$counter = $method . '_count';
				}
				
				$dataset = Executive::doMethodCall($amfbody, $construct, $method, $args); // do the magic
				$count = Executive::doMethodCall($amfbody, $construct, $counter, $args);
				
				//Include the wrapper
				$results = array('class' => $amfbody->uriClassPath, 
								 'method' => $amfbody->methodName, 
								 'count' => $count, 
								 "args" => $args, 
								 "data" => $dataset);
				$amfbody->setMetadata('type', '__DYNAMIC_PAGEABLE_RESULTSET__');
				$amfbody->setMetadata('pagesize', $construct->methodTable[$method]['pagesize']);
				*/
			//}
			//else
			//{
				//The usual
				$results = Executive::doMethodCall($amfbody, $construct, $method, $args); // do the magic
			//}
		}

		if($results !== '__amfphp_error')
		{
			if($specialHandling == 'RemotingMessage')
			{
				$wrapper = generateAcknowledgeMessage($amfbody->getMetadata("messageId"), 
													  $amfbody->getMetadata("clientId"));
				$wrapper->body = $results;
				$amfbody->setResults($wrapper);
			}
			else
			{
				$amfbody->setResults($results);
			}
			
			/*
			if(isset($construct->methodTable[$method]['returns'])
				&& !isset($construct->methodTable[$method]['pagesize']))
			{
				$amfbody->setMetadata('type', $construct->methodTable[$method]['returns']);
			}
			*/
			$amfbody->responseURI = $amfbody->responseIndex . "/onResult";  
		}
		return false;
	}
	elseif($specialHandling == 'Ping')
	{
		$wrapper = generateAcknowledgeMessage($amfbody->getMetadata("messageId"), 
											  $amfbody->getMetadata("clientId"));
		$amfbody->setResults($wrapper);
		$amfbody->responseURI = $amfbody->responseIndex . "/onResult";
	}
	else if($specialHandling == 'pageRelease')
	{
		//Ignore PageAbleResult.release
		$amfbody->setResults(true);
		$amfbody->setMetaData('type', 'boolean');
		$amfbody->responseURI = $amfbody->responseIndex . "/onResult";
		return false;
	}
	return true;
}

/**
 * WebServiceAction calls a remote webservice instead of a regular method
 */
function webServiceAction (&$amfbody) {
	
	$method = $GLOBALS['amfphp']['webServiceMethod'];
	
	if ($amfbody->getSpecialHandling() == 'ws') {
		$args = &$amfbody->getValue();
		$webServiceURI = $amfbody->classPath;
		$webServiceMethod = $amfbody->methodName;
		$phpInternalEncoding = CharsetHandler::getPhpCharset();
		
		$functionName = "webServiceAction_$method";
		
		//Include web service actions
		include_once(AMFPHP_BASE . "app/WebServiceActions.php");
		$results = $functionName($amfbody, $webServiceURI, $webServiceMethod, $args, $phpInternalEncoding);
		if($results != '__amfphp_error')
		{
			$amfbody->setResults($results);
			$amfbody->responseURI = $amfbody->responseIndex . "/onResult";
		}
	}
	return false;
} 

function generateAcknowledgeMessage($messageId = NULL, $clientId = NULL)
{
	$result = new stdClass();
	$result->_explicitType = "flex.messaging.messages.AcknowledgeMessage";
    $result->messageId = generateRandomId();
    $result->clientId = $clientId != NULL ? $clientId : generateRandomId();
    $result->destination = null;
    $result->body = null;
    $result->timeToLive = 0;
    $result->timestamp = (int) (time() . '00');
    $result->headers = new STDClass();
    $result->correlationId = $messageId;
    
    return $result;
}

function generateRandomId()
{
   // version 4 UUID
   return sprintf(
       '%08X-%04X-%04X-%02X%02X-%012X',
       mt_rand(),
       mt_rand(0, 65535),
       bindec(substr_replace(
           sprintf('%016b', mt_rand(0, 65535)), '0100', 11, 4)
       ),
       bindec(substr_replace(sprintf('%08b', mt_rand(0, 255)), '01', 5, 2)),
       mt_rand(0, 255),
       mt_rand()
   );
}
?>